package a02;

import java.awt.Color;
import java.rmi.RemoteException;
import java.util.LinkedList;
import java.util.List;

import util.Pair;

public class OthelloControl extends RegularControl<OthelloMove> implements
	Constants {

    private static final long serialVersionUID = 1L;
    private Othello session;
    private byte[][] lastMoveTable;

    public OthelloControl() {
	this(new Othello());
    }

    public OthelloControl(boolean visible) {
	this(new Othello(), 0, visible);
    }

    public OthelloControl(Othello ttt) {
	this(ttt, 0, true);
    }

    public OthelloControl(Othello ttt, int kiLevel, boolean visible) {
	super(ttt, new OthelloBoard<OthelloMove>(ttt), "Othello", kiLevel,
		visible);
	super.getBoard().setPlayerColors(Color.WHITE, "WEISS", Color.BLACK,
		"SCHWARZ");
	this.setSession(ttt);
	super.getBoard().setTableColor(11, 116, 0);
	super.getBoard().setGrid(new Color(0, 69, 2), 1);
	refresh();
    }

    @Override
    public Othello getNewGame() {
	this.session = new Othello();
	return this.session;
    }

    public Othello getSession() {
	return this.session;
    }

    public void setSession(Othello session) {
	this.session = session;
    }

    @Override
    public boolean isPassingEnabled() {
	return true;
    }

    @Override
    public void pass(boolean remoteMove) {
	getStack().push(this.getBoard().getGame());
	session.pass(this);
	this.getBoard().setLastMove(null);
	if (getServer() != null && !remoteMove) {
	    try {
		this.getServer().setMouseClick((byte) -1, (byte) -1,
			getPlayerID(), PASSEDMOVE);
	    } catch (RemoteException e) {
		System.err.println(e);
	    }
	}
	handleWin();
    }

    @Override
    public boolean isAnyMovePossible() {
	boolean foundOneMove = false;
	for (byte x = 0; x < this.getBoard().getGame().getColumns(); x++) {
	    for (byte y = 0; y < this.getBoard().getGame().getRows(); y++) {
		if (this.getBoard().getGame().setAtPosition(x, y) != this.getBoard().getGame())
		    foundOneMove = true;
		if (foundOneMove)
		    break;		
	    }
	    if (foundOneMove)
		break;
	}
	return foundOneMove;
    }

    @Override
    public void handleWin() {
	if (this.getBoard().getGame().ended() && !isPopUpDone()) {
	    this.setPopUpDone(true);
	    this.getMenu().setStatus("Spiel beendet! ");
	    playSound(Sound.WIN);
	    byte op = this.getBoard().getGame()
		    .otherPlayer(this.getBoard().getGame().currentPlayer());
	    byte cp = this.getBoard().getGame().currentPlayer();
	    if (getServer() == null && isCurrentPlayerWinner()) {
		this.showPopup("GEWONNEN", "Spieler "
			+ this.getBoard().getPlayerColorName(op)
			+ " hat gewonnen! ("
			+ this.getBoard().getGame().evalState(op) + " zu "
			+ this.getBoard().getGame().evalState(cp) + ")");
	    } else if (getServer() == null
		    && this.getBoard().getGame().wins(cp)) {
		this.showPopup("GEWONNEN", "Spieler "
			+ this.getBoard().getPlayerColorName(cp)
			+ " hat gewonnen! ("
			+ this.getBoard().getGame().evalState(cp) + " zu "
			+ this.getBoard().getGame().evalState(op) + ")");
	    } else if (getPlayerID() != 0
		    && (getBoard().getGame().wins(this.getPlayerID()))) {
		this.showPopup("Gewonnen", "Sie haben gewonnen!");

	    } else if (getPlayerID() != 0
		    && (getBoard().getGame().wins(this.getBoard().getGame()
			    .otherPlayer(this.getPlayerID())))) {
		this.showPopup("Verloren", "Sie haben verloren!");
	    } else {
		this.showPopup("Unentschieden", "Leider unentschieden!");
	    }
	}

    }

    public void makeNewLastMoveTable() {
	this.lastMoveTable = convertBoard();
    }

    @Override
    public void executeChanges(byte c, byte r, boolean remoteMove)
	    throws RemoteException {
	if (this.getBoard().getGame().getAtPosition(c, r) != this.getBoard()
		.getGame().getPlayerNone()
		|| (this.getServer() != null && this.getServer().getPlayerID() != this
			.getPlayerID())) {
	    if (this.getBoard().getGame().getAtPosition(c, r) != this
		    .getBoard().getGame().getPlayerNone())
		playSound(Sound.FAIL);
	    return;
	}

	Othello newState = (Othello) this.getBoard().getGame()
		.setAtPosition(c, r);
	if (newState.getAtPosition(c, r) == this.getBoard().getGame()
		.getPlayerNone()) {
	    playSound(Sound.FAIL);

	} else {
	    playSound(Sound.CLICK);
	    makeNewLastMoveTable();
	    this.getStack().push(this.getBoard().getGame());
	    this.setSession(newState);
	    this.getBoard().setGame(newState);
	    if (!(getServer() == null) && !remoteMove)
		this.getServer().setMouseClick(c, r, getPlayerID());
	    this.getBoard().setLastMove(new Pair<Byte, Byte>(c, r));
	    this.getBoard().setLastTaken(findLastTaken());
	    makeNewLastMoveTable();

	}
	getBoard().repaintBufferedImage();
	refresh();
	handleWin();
	if (!this.getStack().isEmpty()) {
	    this.getMenu().setButtonEnabled(true);
	}
    }

    @Override
    public void setGameMode1Player(boolean gameMode1Player) {
	super.setGameMode1Player(gameMode1Player);
    }

    public byte[][] getLastMoveTable() {
	return this.lastMoveTable;
    }

    public List<Pair<Byte, Byte>> findLastTaken() {
	byte[][] thisMoveTable = convertBoard();
	List<Pair<Byte, Byte>> lastTaken = new LinkedList<Pair<Byte, Byte>>();
	for (byte x = 0; x < this.getBoard().getGame().getColumns(); x++) {
	    for (byte y = 0; y < this.getBoard().getGame().getRows(); y++) {
		if (lastMoveTable[x][y] == this.getBoard().getGame()
			.currentPlayer()
			&& thisMoveTable[x][y] == this
				.getBoard()
				.getGame()
				.otherPlayer(
					this.getBoard().getGame()
						.currentPlayer()))
		    lastTaken.add(new Pair<Byte, Byte>(x, y));
	    }
	}
	return lastTaken;
    }

    private byte[][] convertBoard() {
	byte[][] convertedList = new byte[this.getBoard().getGame()
		.getColumns()][this.getBoard().getGame().getRows()];
	for (byte x = 0; x < this.getBoard().getGame().getColumns(); x++) {
	    for (byte y = 0; y < this.getBoard().getGame().getRows(); y++) {
		convertedList[x][y] = this.getBoard().getGame()
			.getAtPosition(x, y);
	    }
	}
	return convertedList;
    }
}
